
import { useEffect,useState,useRef, UIEvent } from 'react'
import { Input, Popover } from 'antd'
import { observer } from 'mobx-react-lite'
import {MessageItem } from '@/components/Message'
import {HoverScroll } from '@/components/Scroll'
import { Setting } from '@/components/DrawSetting'
import { IStyleItem,IFormatItem,TQualityItem,TProduceItem, IDesItem } from '@/types'
import { IAiPicItem, IMessageItem, IResultCheckAiPic, IResultMessgeItem } from '@/components/Message/type'
import { useStore } from '@/store'
import { setPv_new, throttle } from '@/utils'
import { formatMessage, getMsgSuffix } from './utils'
import {qualityList,produceNumber, defaultMessage, MSG_TYPE } from './config'
import { IGetJobData, checkAiDraw, checkHighPreview, closeAiDraw, getAiDrawJob, getChannelMessgeList, getDrawChannels, getFormatStyle, getHighImgJob, getPresetDes, updateMessageStatus, uploadToAsset } from './api'
import './home.moudle.scss';
import { Layout } from '@/components/Layout'
let page = 1;
let isRequesting = false
let isPageAdd = false
function Home() { 
    const store = useStore()
    const [showSetting,setShowSetting] = useState<boolean>(false)
    const [styleList,setStyleList] = useState<IStyleItem[]>([])
    const [formatList, setFormatList] = useState<IFormatItem[]>([])
    const [activeStyle,setActiveStyle] = useState<IStyleItem>({} as IStyleItem)
    const [activeFormat,setActiveFormat] = useState<IFormatItem>({} as IFormatItem)
    const [activeQuality,setActiveQuality] = useState<TQualityItem>(qualityList[0] as TQualityItem)
    const [activeProducer,setActiveProducer] = useState<TProduceItem>(produceNumber[0] as TProduceItem)
    const selectStyle = (style: IStyleItem) => setActiveStyle(style)
    const selectFormat = (format: IFormatItem) => setActiveFormat(format)
    const selectQuality = (quality: TQualityItem) => setActiveQuality(quality)
    const selectProduce = (produce: TProduceItem) => setActiveProducer(produce)
    // 预设关键词
    const [presets, setPresets] = useState<IDesItem[]>([])
    const getPresets = () => { 
        getPresetDes().then(res => { 
            setPresets(res.data.list)
        })
    }
    const getStyleFormat = () => { 
        // 风格，版式
        getFormatStyle().then(res => { 
            const { style, format } = res.data
            setStyleList(style)
            setActiveStyle(style[0])
            setFormatList(format)
            setActiveFormat(format[0])
        }).catch(e => { 
            console.log('获取风格，版式出错',e)
        })
    }
    // 修改提示词
    const [prompt,setPrompt] = useState<string>('')
    const changePrompt = (e:React.FormEvent<HTMLTextAreaElement>) => {
        setPrompt(e.currentTarget.value)
    }
    
    // 点击发送prompt 信息，开始生成 defaultMessage
    const [messageList, setMessageList] = useState<IMessageItem[]>([])
    // 绘图任务队列
    const resultValidate = (res: { code: number },messageIndex:number) => { 
        if (!res.code) {
            changeMessageItem(messageIndex, {
                type: MSG_TYPE.ERROR
            })
        }
        // 如果包含违禁词，直接隐藏最后一条消息
        if (res.code === 10) {
            changeMessageItem(messageIndex, {
                type: MSG_TYPE.PROHIBIT
            })
        }
    }
    // 关闭当前生成好的jobItem
    const downAiJobItem = (messageIndex: number, files: IAiPicItem[],count:number=0) => {
        if (!files.length) return;
        const newPoint = store.user.pointNum - count
        store.user.setUserPoint(newPoint)
        newPoint <= 0 && setPv_new(7608)
        changeMessageItem(messageIndex, {
            type: MSG_TYPE.FINISH,
            step:100,
            picList:files
        })
    }
    // 实时监控ai生成图片状态
    const checkAiDrawJob = (messageIndex:number,jobId:string)=>{
        setTimeout(() => {
            checkAiDraw(jobId).then(res => {
                const checkResult = res.data as IResultCheckAiPic
                const { status, width, height, files = [], time, preview } = checkResult
                switch (status) {
                    case 'WAITING':
                        checkAiDrawJob(messageIndex, jobId)
                        break;
                    case 'RUNNING':
                        changeMessageStep(messageIndex,files)
                        checkAiDrawJob(messageIndex, jobId)
                        break;
                    case 'END':
                    case 'CLOSE':
                    case 'FAIL':
                        const count = files.filter(v=>!v.isdel).length
                        if (['CLOSE', 'FAIL'].includes(status) && !files.length) {
                            const isNetError = status==='FAIL'
                            const isClose = status==='CLOSE'
                            changeMessageItem(messageIndex, {
                                type: isNetError?MSG_TYPE.ERROR:MSG_TYPE.CANCEL
                            },{isNetError,isClose})
                        } else { 
                            if (preview) { 
                                // 合成图
                                files.unshift({
                                    ...files[0],
                                    isSynthesis:true,
                                    preview,
                                    id:Date.now()
                                })
                            }
                            const newFiles = files.map(file => ({ ...file, width, height}))
                            downAiJobItem(messageIndex,newFiles,count)
                        }
                        break;
                }
            }).catch(err => {
                changeMessageItem(messageIndex, {
                    type: MSG_TYPE.ERROR,
                },{isNetError:true})
                console.log('err')
            })
        }, 2000)
    }
    // 虚拟进度条展示
    const changeMessageStep = (messageIndex: number,files:IAiPicItem[]) => { 
        setMessageList((preMessageList) => {
            const { step = 0 } = preMessageList[messageIndex]
            const vStep = Math.floor(Math.random()*15)
            preMessageList[messageIndex] = {...preMessageList[messageIndex],step:step+vStep>=100?step:step+vStep,type:MSG_TYPE.GENERATING}
            return [...preMessageList];
        });
    }
    // 修改当前message的状态
    const changeMessageItem = (messageIndex: number, messageOptions: Partial<IMessageItem>, errInfo?: { isNetError?: boolean; isClose?:boolean}) => { 
        setMessageList((preMessageList) => {
            preMessageList[messageIndex] = { ...preMessageList[messageIndex], ...messageOptions }
            if (errInfo) { 
                if (errInfo.isNetError) {
                    updateMessageStatus({id:preMessageList[messageIndex].id,status:'FAIL'})
                }
                if (errInfo.isClose) { 
                    updateMessageStatus({id:preMessageList[messageIndex].id,status:'CLOSE'})
                }
            }
            
            return [...preMessageList]
        });
    }
    // 添加新的messageItem
    // isReverse 上拉刷新 否则 用户发送消息添加
    const addMesssageItem = (newMessage: IMessageItem | IMessageItem[],isReverse=false) => { 
        isPageAdd = isReverse
        setMessageList((preMessageList) => {
            const newMsg = Array.isArray(newMessage) ? newMessage : [newMessage]
            preMessageList[isReverse?'unshift':'push'](...newMsg)
            return [...preMessageList]
        });
    }
    // 拿到ai绘画的参数
    const getAiJobParams: (param?: IMessageItem) => IGetJobData = (param) => { 
        param = (param || {}) as IMessageItem
        return {
            promt: param.content || prompt,
            style: param.style || activeStyle.style,
            format: param.format || activeFormat.format,
            definition: param.definition || ('' + activeQuality.value),
            channel_id: '' +(param.channel_id || store.user.activeChannel.id),
            //绘图类型 0:ai绘图 1:ai商品图 2:ai绘图编辑器 3:放大
            is_synthesis: param.is_synthesis || '2',
            num:param.num || activeProducer.value
        }
    }
    
    /**
     * 发送用户信息 获取图片生成job，使用job去轮询
     * 或者 点击重新生成直接拿当前的信息的参数重新生成一条任务
     * @param param 重新生成的信息参数
     * @returns 
     */
    
    const sendUserInfo = (param?: IMessageItem) => { 
        const hasReStartParam = !!param
        if (!store.user?.userInfo?.id) { 
            store.user.setOpenLoginModal(true)
            return;
        }
        // 如果是点击重新生成，直接拿当前的信息的参数重新生成一条任务
        if (!hasReStartParam && !prompt.replace(/\s/g, '')) return;
        if (store.user.pointNum < 1) { 
            store.user.changePayModalStatus(true)
            return;
        }
        setPrompt('')
        setShowSetting(false)
        let messageIndex = messageList.length
        const params = getAiJobParams(param)
        const newMessageItem = { 
            type: MSG_TYPE.WATTING,
            content: params.promt as string + (!hasReStartParam?getMsgSuffix(params):''),
            id: '' + Date.now(),
            step: 0,
            num: params.num,
            style: params.style,
            format: params.format,
            definition: params.definition,
            channel_id: ''+params.channel_id,
            //绘图类型 0:ai绘图 1:ai商品图 2:ai绘图编辑器 3:放大
            is_synthesis: params.is_synthesis,
        }
        addMesssageItem(newMessageItem)
        getAiDrawJob(params).then(res => { 
            if (res.code !== 1) { 
                resultValidate(res,messageIndex)
                return
            }
            const { jobId,id} = res.data
            changeMessageItem(messageIndex, {
                type: MSG_TYPE.WATTING,
                job: jobId,
                id
            })
            checkAiDrawJob(messageIndex,jobId)
        })
    }
    // 查看高清大图
    const checkHighPic = (messageIndex:number,jobId:string,picId:number)=> {
        window.setTimeout(() => {
            checkAiDraw(jobId).then(res => {
                const { status, files, width, height } = res.data
                if (status === 'END') {
                    const newPoint = store.user.pointNum - 1
                    store.user.setUserPoint(newPoint)
                    newPoint <= 0 && setPv_new(7608)
                    changeMessageItem(messageIndex, {
                        type: MSG_TYPE.FINISH,
                        step: 100,
                        picList: [{
                            ...files[0],
                            width,
                            height,
                        }]
                    })
                } else if (['FAIL', 'CLOSE'].includes(status)) {
                    const isNetError = status === 'FAIL'
                    const isClose = status === 'CLOSE'
                    changeMessageItem(messageIndex, {
                        type: isNetError ? MSG_TYPE.ERROR : MSG_TYPE.CANCEL,
                    }, {isNetError,isClose})
                } else if (status !== 'CLOSE') {
                    changeMessageStep(messageIndex,files)
                    // 点击取消ai文案生成，不再轮询
                    checkHighPic(messageIndex,jobId,picId)
                }
            }).catch(err => {
                changeMessageItem(messageIndex, {
                    type: MSG_TYPE.ERROR,
                }, {isNetError:true})
            })
        }, 2000)
    }
    const getHighPic = (pic: IAiPicItem,msg:IMessageItem) => { 
        let messageIndex = messageList.length
        const newMessageItem = { type: MSG_TYPE.WATTING,isBig:true, content:msg.content, id: MSG_TYPE.WATTING }
        addMesssageItem(newMessageItem)
        getHighImgJob(pic.id).then(res => { 
            const { jobId,id} = res.data
            changeMessageItem(messageIndex, {
                type: MSG_TYPE.GENERATING,
                pid:msg.id,
                id,
                job: jobId
            })
            checkHighPic(messageIndex,jobId,pic.id)
        })
    }
    // 历史记录
    const getMessageList = () => { 
        isRequesting = true
        getChannelMessgeList({
            channelId: store.user.activeChannel.id,
            page: page,
            created: Date.now()
        }).then(res => {
            isRequesting = false
            if (!res.data.length) { 
                if (!messageList.length) { 
                    addMesssageItem(defaultMessage, true)
                    return;
                }
                // 如果没有返回消息，并且默认消息已经存在消息列表
                if (messageList[0].id === 'DEFAULT_MESSAGE' && messageList.length) return;
                addMesssageItem(defaultMessage, true)
                return;
            }
            
            const { formatList: newMessageList, jobList } = formatMessage(res.data, messageList.length)
            let newMessage: IMessageItem[] = [...newMessageList]
            // 不足一页，需显示默认信息放在第一条
            if (res.data.length < 20) { 
                newMessage = [defaultMessage, ...newMessageList]
                jobList.forEach(job => { 
                    job.index+= 1
                })
            }
            addMesssageItem(newMessage, true)
            // 轮询未完成的任务
            jobList.forEach(jobInfo => { 
                if (jobInfo.isBig) {
                    checkHighPic(jobInfo.index, jobInfo.jobId, Date.now())
                } else {
                    checkAiDrawJob(jobInfo.index, jobInfo.jobId)
                }
            })
        })
    }

    // 处理信息自动定位地步
    const messageContentboxRef = useRef()
    const autoPos = (scrollTop?:number) => { 
        const contentRef = messageContentboxRef.current
        if (!contentRef) return;
        (contentRef as unknown as  {autoScrollTop:(scrollTop?:number)=>void}).autoScrollTop(scrollTop)
    }
    // 父级消息定位
    const messgeListRef = useRef<HTMLDivElement>(null)
    const toParentPos = (pid:string) => { 
        const parentMessageIndex = messageList.findIndex(msg => msg.id === pid)
        const listDom = messgeListRef.current as HTMLDivElement
        const parentDom = listDom.childNodes[parentMessageIndex]
        const scrollTop = (parentDom as HTMLDivElement).offsetTop
        autoPos(scrollTop)
    }
    useEffect(() => { 
        if (!store?.user?.activeChannel?.id) return
        getMessageList()
    },[store.user.activeChannel.id])
    useEffect(() => { 
        getStyleFormat()
        getPresets()
        //监听dom渲染完毕专用
        const targetNode = messgeListRef.current;
        const resizeObserver = new ResizeObserver((entries) => {
            if (isPageAdd && page !== 1) return;
            autoPos()
        });
        
        resizeObserver.observe(targetNode as HTMLDivElement);
        // 在组件卸载时停止观察
        return () => {
            if (targetNode) {
                resizeObserver.disconnect();
            }
        };
    }, [])
    // 重新生成
    const onReStart = (message: IMessageItem, messageIndex: number) => { 
        sendUserInfo(message)
    }
    // 选择预设 
    const selectPreset = (preset: IDesItem) => { 
        setPrompt(preset.des)
        const findStyle = styleList.find(style => style.style === preset.style)
        setActiveStyle(findStyle as IStyleItem)
        setShowSetting(true)
    }
    // 跳到编辑
    const toEditPage = (pic: IAiPicItem) => {
        let width: number
        let height: number
        let uaId:string;
        const img = new Image()
        img.src = pic.preview
        img.onload = () => { 
            width = img.width
            height = img.height
            if (uaId)JumpUrl()
        }
        uploadToAsset(pic.id).then(res => {
            uaId = res.data['ua-id']
            if (width)JumpUrl()
        })
        function JumpUrl() { 
            const pram = window.btoa(`{"path":"${pic.preview}"}`)
            window.open(`//ue.818ps.com/v4/?w=${width}&h=${height}&origin=home_tgsai_nav_ai&user_asset_id=UA-${uaId}&user_asset_id_2=UA-${uaId}&pram=${pram}`,'_blank')
        }
    }
    // 滚动分页
    const onScroll = throttle((event: UIEvent<HTMLDivElement>) => { 
        const contentRef = messageContentboxRef.current
        if (!contentRef) return;
        const messageCutboxRef = (contentRef as unknown as { cutboxRef: {current:HTMLDivElement} })
        const cutBoxRef = (messageCutboxRef.cutboxRef.current as HTMLDivElement)
        if (cutBoxRef) { 
            const scrollTop = cutBoxRef.scrollTop;
            if (scrollTop <= 0) { 
                if (isRequesting) return;
                page++;
                getMessageList()
            }
        }
    })

    // 取消任务
    const closeJob = (message: IMessageItem, messageIndex: number) => { 
        setPv_new(7595)
        closeAiDraw(message.job as string)
    }

    return (
        <Layout>
            <div className="aiMessage">
                <HoverScroll height={'calc(100vh - 56px - 100px)'} ref={messageContentboxRef} onScroll={onScroll}>
                    <div className="messageList" ref={messgeListRef}>
                        {messageList.map((msg, index) => {
                            return (<MessageItem
                                key={msg.id}
                                index={index}
                                message={msg}
                                presets={presets}
                                onRefreshPresets={getPresets}
                                onSelectPreset={selectPreset}
                                onCloseJob={closeJob}
                                onToEdit={toEditPage}
                                onToParent={toParentPos}
                                onGetHighPic={getHighPic}
                                onReStart={onReStart}
                            ></MessageItem>)
                        })}
                    </div>
                </HoverScroll>
                <div className="inputMessage">
                    <div className="label" onClick={() => {
                        setShowSetting(!showSetting)
                    }}>
                        <span>文生图</span>
                        <i className='iconfont icon-shezhixuanxiang-01'></i>
                        <Setting
                            show={showSetting}
                            onShowSetting={setShowSetting}
                            styleList={styleList}
                            formatList={formatList}
                            qualityList={qualityList}
                            produceNumber={produceNumber}
                            activeStyle={activeStyle}
                            activeFormat={activeFormat}
                            activeQuality={activeQuality}
                            activeProducer={activeProducer}
                            selectStyle={selectStyle}
                            selectFormat={selectFormat}
                            selectQuality={selectQuality}
                            selectProduce={selectProduce}
                        ></Setting>
                    </div>
                    <div className="inputArea">
                        <div className="inputBox">
                            <Input.TextArea autoSize={{ maxRows: 4 }} value={prompt} onInput={changePrompt} placeholder="请输入提示词" />
                        </div>
                        <Popover content={`每次消耗${activeProducer.value}点`} getPopupContainer={triggerNode => triggerNode.parentElement as HTMLElement}>
                            <div className="btn" onClick={() => {
                                setPv_new(7594)
                                sendUserInfo()
                            }}>
                                <i className='iconfont icon-fasong'></i>
                                <span>发送</span>
                            </div>
                        </Popover>

                    </div>

                </div>
            </div>
        </Layout>
    )
}

export default observer(Home)